// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::structure::*;
use core::cell::RefCell;
use std::rc::Rc;

/// `NodeList` structure, which corresponds to the `Interface NodeList`.
/// Users generally do not create `NodeList` directly, but obtain it from the
/// return value of some methods.
///
/// # Association
/// [Interface NodeList](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-7D61178C)
///
/// # Example
/// ```
/// use ylong_xml::{Document, ParentNodeMethod};
///
/// let document = Document::new();
/// let children = document.children();
/// assert_eq!(children.len(), 0);
/// ```
#[derive(Debug, Clone)]
pub struct NodeList<T> {
    pub(crate) list: Rc<RefCell<Vec<T>>>,
}

impl<T: ChildNodeMethod + Clone> NodeList<T> {
    /// Get the number of nodes in the list.
    ///
    /// # Association
    /// [Interface NodeList](https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-203510337)
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, ParentNodeMethod};
    ///
    /// let document = Document::new();
    /// let children = document.children();
    /// assert_eq!(children.len(), 0);
    /// ```
    pub fn len(&self) -> usize {
        self.list.borrow().len()
    }

    /// Check if a `NodeList` is empty.
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, ParentNodeMethod};
    ///
    /// let document = Document::new();
    /// let children = document.children();
    /// assert_eq!(children.is_empty(), true);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.list.borrow().is_empty()
    }

    /// Return the `index`th item in the collection. If `index` is greater than
    /// or equal to the number of nodes in the list, this returns `None`.
    ///
    /// # Example
    /// ```
    /// use ylong_xml::{Document, ParentNodeMethod};
    ///
    /// let document = Document::new();
    /// let children = document.children();
    /// assert!(children.item(0).is_none());
    /// ```
    pub fn item(&self, index: usize) -> Option<T> {
        self.list.borrow().get(index).cloned()
    }

    /// Create a `NodeList`.
    pub(crate) fn new(list: Vec<T>) -> Self {
        Self {
            list: Rc::new(RefCell::new(list)),
        }
    }

    /// Get the first item of the list.
    pub(crate) fn first(&self) -> Option<T> {
        self.list.borrow().first().cloned()
    }

    /// Get the last item of the list.
    pub(crate) fn last(&self) -> Option<T> {
        self.list.borrow().last().cloned()
    }
}

impl<T> Default for NodeList<T> {
    fn default() -> Self {
        Self {
            list: Rc::new(RefCell::new(Vec::new())),
        }
    }
}
